Namespace Internals
	''' <summary>
	''' Provides base methods to parse a result block
	''' (hg.Net by Wesley Werner)
	''' </summary>
	''' <remarks></remarks>
	Public MustInherit Class ResultBase
		Inherits Collections.Generic.List(Of ResultDetail)


#Region " properties "

		''' <summary>
		''' The result text for this item, usually a multiline block of text
		''' </summary>
		''' <value></value>
		''' <returns></returns>
		''' <remarks></remarks>
		Public Property Result() As String
			Get
				Return _Result
			End Get
			Set(ByVal value As String)
				_Result = value
			End Set
		End Property
		Private _Result As String

#End Region


		''' <summary>
		''' Implement this method to parse the lines for your inherited result class
		''' </summary>
		''' <remarks>Use the Parse_Value() method to extract details from the result text</remarks>
		MustOverride Sub Parse_Lines()


		''' <summary>
		''' Splits the given output text into individual result blocks
		''' </summary>
		''' <returns></returns>
		''' <remarks></remarks>
		Shared Function Parse_Result_Blocks(ByVal result_text As String, Optional ByVal delimiter As String = hgNet.Constants.EOR) As List(Of String)

			Dim blocks As New List(Of String)
			Dim idx As Integer = 0
			Dim idx_e As Integer = 0
			idx = result_text.IndexOf(delimiter, 0)

			While (idx > -1)
				blocks.Add(result_text.Substring(idx_e, idx - idx_e))
				idx_e = idx + delimiter.Length - "changeset:".Length
				idx = result_text.IndexOf(delimiter, idx_e)
			End While

			' Get the last block (only if there are results)
			If result_text.Length > 0 Then
				blocks.Add(result_text.Substring(idx_e))
			End If

			Return blocks

		End Function


		''' <summary>
		''' Get a list of keys in this list
		''' </summary>
		''' <returns></returns>
		''' <remarks></remarks>
		Public Function Get_Keys() As List(Of String)
			Dim keys As New List(Of String)
			For Each item As ResultDetail In Me
				keys.Add(item.Key)
			Next
			Return keys
		End Function


		''' <summary>
		''' Gets or sets a result detail
		''' </summary>
		''' <param name="key">the key of the item to get or set</param>
		''' <value></value>
		''' <returns></returns>
		''' <remarks></remarks>
		Default Public Overloads Property Item(ByVal key As String) As ResultDetail
			Get
				For Each foo As ResultDetail In Me
					If (foo.Key = key) Then
						Return foo
					End If
				Next
				Return Nothing
			End Get
			Set(ByVal value As ResultDetail)
				For Each foo As ResultDetail In Me
					If (foo.Key = key) Then
						foo = value
					End If
				Next
			End Set
		End Property


		''' <summary>
		''' Create a new result item
		''' </summary>
		''' <param name="result_text">The result text to parse</param>
		''' <remarks></remarks>
		Sub New(ByVal result_text As String)
			Me.Result = result_text
			Parse_Lines()
			CleanUp()
		End Sub


		''' <summary>
		''' Remove empty results from me
		''' </summary>
		''' <remarks></remarks>
		Private Sub CleanUp()
			Dim idx As Integer = 0
			While (Me.Count > 0)
				If IsNothing(Me(idx)) Then
					Me.RemoveAt(idx)
					' dont up the index, the list was moved up to this emptied idx
				Else
					idx += 1
				End If
				' stop when we reach the 
				If (idx = Me.Count) Then Exit While
			End While
		End Sub


		''' <summary>
		''' Parses the result for the given key
		''' </summary>
		''' <param name="key">This is the start of the result line: changeset, user, date, description...</param>
		''' <param name="line_delimiter">delimits each key/value pair</param>
		''' <param name="key_delimiter">delimits each key/value</param>
		''' <returns>The queried detail, or Nothing if the key was not found</returns>
		''' <remarks></remarks>
		Public Function Parse_Value(ByVal key As String, Optional ByVal line_delimiter As String = hgNet.Constants.EOL, Optional ByVal key_delimiter As Char = ":"c) As ResultDetail

			' the key must end with a colon to conform to the output standard
			If Not key.EndsWith(key_delimiter) Then key = String.Concat(key, key_delimiter)

			' search for the key
			Dim idx As Integer = Me.Result.IndexOf(key)

			' if the key is found
			If (idx > -1) Then

				' the value starts *after* the key postion, including the key itself
				idx += key.Length

				' determine the end position, this is a LF char
				Dim end_idx As Integer = Me.Result.IndexOf(line_delimiter, idx)

				' an invalid end position is taken as the end of the text
				If (end_idx = -1) Then end_idx = Me.Result.Length

				' get the key value
				Dim value As String

				' get the value, the length is taken as end - begin
				value = Me.Result.Substring(idx, end_idx - idx)

				' strip any unwanted spaces
				value = value.Trim

				' revert the key to a cleaner state
				key = key.Trim(key_delimiter)

				' add the item
				Return New ResultDetail(key, value)

			Else
				Return New ResultDetail(key.Trim(key_delimiter), "")
			End If

		End Function


	End Class
End Namespace
